Optimal (Ramsey) policy ======================= When the model file contains an **optimization-problem** block, RISE treats the policy as the solution to a planner's problem rather than as a fixed equation: one (or more) of the policy equations is replaced by the planner's first-order conditions. RISE handles several flavours of this: - **commitment** (Ramsey policy), with or without regime switching; - **discretion**, linear-quadratic or nonlinear, with or without regime switching; - **loose commitment** -- switching between commitment and discretion with a constant probability, in a linear-quadratic system; - **stochastic replanning** -- switching between commitment and discretion with possibly time-varying probabilities, in a nonlinear system; - **non-cooperative games** with multiple policymakers, Nash or Stackelberg, and in the Nash case with a further choice between *open-loop equilibrium* (OLE, the historical default) and *Markov-perfect equilibrium* (MPE) -- selected at solve time, see below. If instead you want to keep all the model equations and only pick the coefficients of a given (e.g. Taylor) rule optimally, see :doc:`../OSR/OptimizedSimpleRules`. Declaring the planner's problem ------------------------------- The objective and the policy type are declared with the ``@optimization_problem`` block (formerly ``@planner_objective``). When this block is present, the number of equations must be strictly less than the number of endogenous variables -- the missing equations are the planner's optimality conditions, generated by RISE. In skeletal form:: @optimization_problem[@no_u_turn = false, @commitment = 1]{ @objective = pi_c^2 + y^2, @discount = beta } The most relevant options are ``@commitment`` (``1`` = commitment/Ramsey, ``0`` = discretion; default ``1``), ``@no_u_turn`` (set ``true`` if you will *only* solve commitment/loose-commitment problems -- it disables the discretion and stochastic-replanning algorithms but is cheaper), ``@markov_process`` (the Markov process controlling the game; default ``"const"`` -- no switches), and the core problem settings ``@objective`` and ``@discount``. The full syntax, including the core problem settings and the regime-switching cases, is in the model-language reference: see :doc:`../Model Language/rise or dsge model language` (the *@optimization_problem block* section). Choosing the policy type at solve time -------------------------------------- If the block does not pin the type down (e.g. ``@optimization_problem[]{ @objective = ..., @discount = beta }``), select it on the model object before solving:: m = set(m, 'solve_policy_type', 'discretion'); % or 'commitment' Then ``solve``, ``stoch_simul``, ``irf``, ``estimate``, ... behave as usual -- the only difference is which equilibrium they impose. RISE picks an appropriate solver automatically: - for a constant-parameter problem that eigenvalue methods can handle: the default RISE solver ``rise_1`` (note that discretion can also be solved with ``rise_1``, conditional on the solution of the forward-looking variables); - for a regime-switching problem: the functional-iteration solver ``mfi``; - when ``@no_u_turn = true``: only ``loose_commitment`` is appropriate -- it works well in linear-quadratic setups but is less accurate for nonlinear problems, and higher-order perturbation cannot be used. You can override the choice with ``set(m, 'solver', '...')``. Loose commitment and stochastic replanning ------------------------------------------ These are set up as two-state Markov-switching problems in which a parameter called ``commitment`` indicates the active mode (``1`` = commitment, ``0`` = discretion). For **loose commitment** (constant probability, linear-quadratic), add a two-state chain and ``@no_u_turn = true``:: @optimization_problem[@no_u_turn = true]{ @objective = pi_c^2 + y^2, @discount = beta } @parameters(looseCommit, 2) commitment @parameters looseCommit_tp_1_2, looseCommit_tp_2_1 (the chain name is arbitrary; the chain must have exactly two states; you choose which state has ``commitment = 1``). For **stochastic replanning** (possibly time-varying probability, nonlinear), use ``@no_u_turn = false`` and let the transition probabilities be endogenous or exogenous:: @optimization_problem[@no_u_turn = false]{ @objective = pi_c^2 + y^2, @discount = beta } @parameters(stochrepl, 2) commitment Again, the model-language reference has the full details (including how to constrain ``looseCommit_tp_1_2 = 1 - looseCommit_tp_2_1`` for estimation). Non-cooperative games: OLE vs MPE --------------------------------- When the ``@optimization_problem`` block declares more than one policymaker (see the *Multiple Policymakers* section of :doc:`../Model Language/rise or dsge model language` for the model-file syntax), RISE supports two non-cooperative equilibrium concepts: - **Open-loop equilibrium (OLE)** -- the historical default. Each player optimises against the opponent's *path*. The forward-shadow row of every player's first-order condition is the standard forward-multiplier term ``beta * lambda(t+1) * f_3``. - **Markov-perfect equilibrium (MPE)** -- each player optimises against the opponent's *policy function*. The forward-shadow row picks up an additional cross-player chain-rule term that captures how the opponent's instrument responds to the predetermined state. For a single-player problem the cross-chain is empty and MPE coincides with OLE exactly (Proposition 3 of the implementation note). You select the equilibrium concept at solve time:: m = solve(m, 'solve_policy_equilibrium', 'OLE'); % default m = solve(m, 'solve_policy_equilibrium', 'MPE'); The option is case-insensitive. There is no ``@ole`` / ``@mpe`` model-file syntax: the model file declares the game (one objective per player, each with its own ``@instrument``, ``@order``, ``@discount`` and ``@objective``); the equilibrium concept is chosen on the model object before solving, in the same spirit as ``solve_policy_type`` selects commitment vs discretion. The two options are independent: all four combinations ``(solve_policy_type, solve_policy_equilibrium) in {ramsey, discretion} x {OLE, MPE}`` are supported in principle. .. note:: The MPE option only changes the FOC for *multi-player* problems, and only on the rows corresponding to **predetermined state variables** (variables that appear at ``{t-1}`` in the model). For single-player models, or on FOC rows for non-state variables (instruments, current-period jumps), the MPE contribution is zero and the FOC reduces to OLE term-by-term. .. note:: Internally MPE is implemented as a small symbolic addition to each relevant FOC row -- no extra endogenous variables are declared, the augmented system has the same size as the OLE-only system, and at ``solve_policy_equilibrium='OLE'`` (the default) RISE produces byte-identical results to releases that did not have the option. Restrictions ~~~~~~~~~~~~ - **Stochastic-replanning models reject the option.** Loose-commitment and stochastic-replanning models are managed through the ``commitment`` switching parameter and a Markov chain. ``set(m, 'solve_policy_equilibrium', ...)`` errors when the model is a stochastic-replanning model. These model classes retain their existing OLE-equivalent behaviour. - **``@no_u_turn = true`` makes the MPE addition a no-op.** The ``@no_u_turn = true`` option asks RISE to skip the entire discretion-derivative pipeline (the ``f1942`` machinery) in exchange for a cheaper parse. The MPE cross-chain is built from that same machinery, so under ``@no_u_turn = true`` the cross-chain contribution silently degenerates to zero and the FOC is the ordinary OLE FOC. This is intentional: ``@no_u_turn = true`` is the option that asks for "no discretion derivatives at all," which is inconsistent with the MPE concept. If you want MPE, leave ``@no_u_turn`` at its default (``false``). - **Single-player consistency.** With one player, MPE = OLE by construction. Toggling the option has no observable effect. - **Stackelberg.** The Stackelberg cascade is handled correctly without any user action. The follower's set of differentiation variables already includes the leader's instruments and multipliers (this is part of the existing optimal-policy pipeline), so the cross-chain is correctly built over the same-level Nash opponents only. The mathematical derivation, the equivalence with an alternative formulation that introduces the value-function gradient as an explicit endogenous state, and the audit trail are recorded in the toolbox repository under ``development/SpecificThings/mpe_ole_implementation/``. Nash commitment fragility (Tatiana) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The smallest fixture that exercises every ``(policy, solve_policy_type, solve_policy_equilibrium)`` combination is Tatiana's monetary-fiscal game, distributed with the regression suite at ``rise-stable-tests/models/dsge/optimal_policy/non-cooperative games/small example refactored/``. The model file ``tatiana.rs`` declares four policy branches behind a ``rise_flags`` switch -- ``cooperative``, ``nash``, ``M_leader``, ``F_leader`` -- without pinning commitment or the equilibrium concept, so the ``{ramsey, discretion} x {OLE, MPE}`` cross-product is selectable on the model object. This yields a 4 x 2 x 2 = 16-cell cube, locked in by ``test_tatiana_policy_equilibria.m`` in the same folder. **The model.** Tatiana is a three-equation linearized monetary-fiscal model with five endogenous variables -- output gap ``X``, inflation ``PI``, the policy rate ``I``, a fiscal instrument ``TAU``, and government debt ``B`` -- driven by three shocks (demand ``E_D``, cost-push ``E_PI``, fiscal ``E_TAU``):: % IS curve X{t} = X{t+1} - (1/sigma)*(I{t} - PI{t+1}) + alpha*B{t} + E_D{t}; % Phillips curve PI{t} = beta*PI{t+1} + kappa*X{t} + kappa_tau*TAU{t} + E_PI{t}; % Fiscal constraint B{t} = (1/beta)*B{t-1} + (tau/beta)*X{t} + (chi/beta)*PI{t} ... - chi*I{t} + TAU{t} + E_TAU{t}; Two policymakers can act on this block. A **monetary** authority chooses ``I`` to minimize ``rho_pi*PI^2 + omega_x*X^2 + omega_i*I^2`` (inflation weight, output-gap weight, interest-rate smoothing) and a **fiscal** authority chooses ``TAU`` to minimize ``PI^2 + omega_x*X^2 + omega_tau*TAU^2`` (inflation weight, output-gap weight, tax smoothing); both discount at ``beta``. The four ``policy`` branches differ in how the two players interact: - ``cooperative`` -- a single planner with objective ``rho_pi*PI^2 + omega_x*X^2 + omega_i*I^2``, picking both ``I`` and ``TAU`` jointly (the cooperative objective is the monetary loss, so the comparison against the Nash branch is apples-to-apples on the monetary side). - ``nash`` -- both authorities are ``@order = 1`` and choose simultaneously. - ``M_leader`` -- Stackelberg with Monetary as the ``@order = 1`` leader and Fiscal as the ``@order = 2`` follower. - ``F_leader`` -- Stackelberg with Fiscal as the ``@order = 1`` leader and Monetary as the ``@order = 2`` follower. The standard calibration (used by the regression test and by the worked example in ``development/profiling/mpe_vs_ole_for_tatiana.zip``) is ``beta = 0.99``, ``sigma = 1.0``, ``kappa = 0.1``, ``kappa_tau = 0.05``, ``alpha = 0.2``, ``chi = 0.3``, ``tau = 0.1``, ``rho_pi = 1.5``, ``omega_x = 0.5``, ``omega_i = 0.1``, ``omega_tau = 0.2``. At the standard calibration the cube partitions as follows: - **Cooperative + {ramsey, discretion} + {OLE, MPE}** -- all four cells solve; MPE = OLE in each (single player, cross-chain empty). - **M_leader / F_leader + {ramsey, discretion} + {OLE, MPE}** -- all eight Stackelberg cells solve; MPE = OLE in each (one player per Stackelberg level, same-level cross-chain empty). - **Nash + discretion + {OLE, MPE}** -- both cells solve; this is the only branch where MPE != OLE, because two players at the same Nash level activate the cross-chain. - **Nash + ramsey + {OLE, MPE}** -- both cells return retcode 24 ("Explosive solution") at this calibration. This is a property of the simultaneous-commitment fixed point, not a toolbox bug. **Why MPE = OLE except in Nash + discretion.** As noted under *Stackelberg* above, the MPE cross-chain only fires for same-level Nash opponents. Cooperative cells have a single player, so the cross-chain is empty by Proposition 3 and the FOC reduces to OLE term-by-term. The Stackelberg cases have exactly one player per level (Monetary or Fiscal alone at ``@order=1``, the other alone at ``@order=2``), so the same-level cross-chain is again empty and the MPE addition is zero on every FOC row. Only the Nash branch puts two players at the *same* level; at this calibration that branch solves only under discretion, which is therefore the lone cell in which the OLE and MPE solutions are observably different. **Why Nash + commitment is explosive.** The simultaneous-commitment fixed point requires Monetary and Fiscal best responses to be mutually consistent under full commitment to the entire forward path. With finite weights on the two instruments and finite cross-elasticities (``kappa_tau``, ``chi``, ``alpha``), the combined system's stable manifold can collapse below the number of predetermined states and the linear perturbation returns *retcode 24 -- explosive solution*. The toolbox is healthy: Stackelberg commitment stabilizes the same model because the leader internalizes the follower's reaction, and Nash discretion stabilizes it because period-by-period reoptimization strips the forward-multiplier dynamics that drive the instability. The same calibration that explodes under ``nash + ramsey`` solves cleanly under ``M_leader + ramsey``, ``F_leader + ramsey``, ``nash + discretion``, and every cooperative cell. **Workflow.** The policy branch is a parse-time choice (via ``rise_flags``); commitment vs discretion is a post-parse choice (via ``solve_policy_type``); OLE vs MPE is a solve-time choice (via ``solve_policy_equilibrium``):: % parse-time: pick the policy branch m = rise('tatiana', 'rise_flags', {'policy', 'nash'}); % ^^^^^^ or cooperative / M_leader / F_leader % post-parse: pick commitment vs discretion m = set(m, 'parameters', params, ... 'solve_policy_type', 'discretion'); % or 'ramsey' % solve-time: pick the equilibrium concept [m, retcode] = solve(m, 'solve_policy_equilibrium', 'MPE'); % or 'OLE' .. note:: If a multi-player calibration of your own returns ``retcode 24`` under ``nash + ramsey``, this is the canonical Tatiana fragility, not a toolbox bug. Before reporting an issue, verify that Stackelberg commitment (``M_leader`` or ``F_leader`` + ``ramsey``) and Nash discretion both solve at the same parameters -- if they do, the simultaneous-commitment fixed point is the unstable one and the model needs either a leader-follower structure or discretion. Welfare and comparing policies ------------------------------ Once a model with an optimization-problem block is solved, evaluate the planner's value with ``calculate_loss``:: [welf, retcode] = calculate_loss(m, lossstr); % unconditional [welf, retcode] = calculate_loss(m, lossstr, shocks_db); % conditional where ``lossstr`` is the loss/objective expression (use the same expression as in ``@objective``). To compare commitment vs discretion vs loose commitment, build the corresponding model objects (e.g. via ``set(m,'solve_policy_type',...)`` or by varying the loose-commitment probability) and compare their losses, or their impulse responses (``irf``) and simulated paths (``simulate`` / ``stoch_simul``). For the trade-off between volatilities as a preference weight varies, use ``frontier`` (see :doc:`../OSR/OptimizedSimpleRules`). Worked example: Ramsey optimal capital taxation ------------------------------------------------ This example -- the optimal-policy problem from Kamenik's Dynare++ tutorial -- is a Ramsey (full-commitment) capital-taxation problem. A planner chooses the capital tax ``TAU`` (whose revenue finances a public good ``G``) to maximise utility from private consumption ``C`` and the public good ``G``, subject to the competitive-equilibrium constraints: capital accumulation, the public-good identity ``G = TAU*alpha*K^alpha``, an AR(1) technology ``Z``, and the representative agent's Euler equation. The model file is:: @endogenous C G K TAU Z @exogenous EPS @parameters eta beta alpha delta phi a rho @optimization_problem{@objective = C^(1-eta)/(1-eta) + a*G^(1-phi)/(1-phi), @discount = beta} @model K = (1-delta)*K{-1} + (exp(Z{-1})*K{-1}^alpha - C{-1} - G{-1}); G = TAU*alpha*K^alpha; Z = rho*Z{-1} + EPS; C^(-eta) = beta*C{+1}^(-eta)*(1-delta + exp(Z{+1})*alpha*K{+1}^(alpha-1)*(1-alpha*TAU{+1})); @parameterization eta = 2; beta = 0.99; alpha = 0.3; delta = 0.10; phi = 2.5; a = 0.1; rho = 0.7; Note that the ``@model`` block lists only the *constraints* (the competitive equilibrium); RISE forms the planner's first-order conditions and Lagrange multipliers automatically from the ``@optimization_problem`` block. Because the model is nonlinear, the steady state must be found from a positive initial guess (the default start is where ``C^(-eta)`` is not finite). Supply one through ``sstate_bounds`` (``[init, lower, upper]`` per variable) and solve under full commitment (``'ramsey'``):: m = rise('ramsey_tax','max_deriv_order',3); % allow a higher-order solve later b = struct(); b.C = [0.77, 0.01, inf]; b.G = [0.31, 0.01, inf]; b.K = [2.90, 0.01, inf]; b.TAU = [0.75, 0.001, 0.99]; [mc, rc] = solve(m, 'solve_policy_type', 'ramsey', 'sstate_bounds', b); The Ramsey steady state -- capital taxed at about 76% to finance the public good, since there is no other revenue source -- is:: C = 0.7744 G = 0.3119 K = 2.9004 TAU = 0.7554 Z = 0 Impulse responses to the technology shock follow from ``irf(mc)``. Because the problem is nonlinear, a higher-order approximation is available for the same model by passing ``solve_order`` (``max_deriv_order`` above must be at least as large):: mc3 = solve(m, 'solve_policy_type', 'ramsey', 'sstate_bounds', b, 'solve_order', 3); .. note:: **Discretion and this model.** Solving the same problem under ``'discretion'`` fails, and this is an economic feature rather than a numerical accident: discretionary *capital* taxation is the classic time-inconsistency / capital-levy problem -- a planner re-optimising each period wants to expropriate already-accumulated capital, so the discretionary steady state is degenerate. A clean commitment-vs-discretion comparison therefore needs a *stabilisation* model (e.g. a small New Keynesian one), as below. Worked example: comparing policy types in a New Keynesian model --------------------------------------------------------------- To compare *commitment*, *discretion* and *loose commitment / stochastic replanning* we need a stabilisation problem in which discretion is well-behaved (unlike the capital-tax model above). A 3-equation New Keynesian model serves: an IS curve, a Phillips curve with a cost-push shock, and a quadratic planner loss in inflation and the output gap, with the nominal rate ``R`` as the instrument:: @endogenous PAI Y R U @exogenous E_PAI @parameters beta kappa sigma lambda rho_u sig_u @optimization_problem{@objective = -0.5*(PAI^2 + lambda*Y^2), @discount = beta} @model Y = Y{+1} - (1/sigma)*(R - PAI{+1}); % IS curve (R is the instrument) PAI = beta*PAI{+1} + kappa*Y + U; % Phillips curve U = rho_u*U{-1} + sig_u*E_PAI; % cost-push shock @parameterization beta = 0.99; kappa = 0.1; sigma = 1; lambda = 0.25; rho_u = 0.5; sig_u = 1; **Commitment** and **discretion** are selected on this model through ``solve_policy_type``:: m = rise('nk_opt'); mc = solve(m, 'solve_policy_type', 'ramsey'); % commitment md = solve(m, 'solve_policy_type', 'discretion'); % discretion **Loose commitment / stochastic replanning** is obtained by making the degree of commitment a switching parameter: declare a two-state ``looseCommit`` chain with a ``commitment`` parameter equal to ``1`` in the "commit" state and ``0`` in the "reoptimise" state, and give it transition probabilities. RISE then uses its loose-commitment solver automatically:: @parameters looseCommit_tp_1_2 looseCommit_tp_2_1 @parameters(looseCommit,2) commitment ... @parameterization commitment(looseCommit,1) = 1; % commit commitment(looseCommit,2) = 0; % reoptimise looseCommit_tp_1_2 = 0.1; looseCommit_tp_2_1 = 0.9; :: mlc = solve(rise('nk_opt_lc')); Rank the policies by the unconditional planner loss (lower is better), evaluated with ``calculate_loss`` on the loss expression:: loss = '0.5*(PAI^2 + lambda*Y^2)'; Lc = calculate_loss(mc, loss); Ld = calculate_loss(md, loss); Llc = calculate_loss(mlc, loss); which reproduces the textbook ordering -- commitment dominates loose commitment, which dominates discretion: .. list-table:: :header-rows: 1 :widths: 60 40 * - policy - unconditional loss * - commitment - 205.5 * - loose commitment / replanning - 235.2 * - discretion - 358.3 Impulse responses to the cost-push shock follow from ``irf(mc)``, ``irf(md)``, ``irf(mlc)`` and can be overlaid to see how commitment damps inflation more aggressively than discretion. The model files and a runnable driver are kept under ``models/dsge/optimal_policy/worked_examples/nk_monetary_policy`` in the test repository.